home *** CD-ROM | disk | FTP | other *** search
- _PORTING UNIX TO THE 386: DEVICE DRIVERS_
- by William Jolitz and Lynne Jolitz
-
-
- [LISTING ONE]
-
- /* [Excerpted from /sys/i386/isa/icu.h] */
- ...
- /* Interrupt enable bits -- in order of priority */
- #define IRQ0 0x0001 /* highest priority - timer */
- #define IRQ1 0x0002
- #define IRQ_SLAVE 0x0004
- #define IRQ8 0x0100
- #define IRQ9 0x0200
- #define IRQ2 IRQ9
- #define IRQ10 0x0400
- #define IRQ11 0x0800
- #define IRQ12 0x1000
- #define IRQ13 0x2000
- #define IRQ14 0x4000
- #define IRQ15 0x8000
- #define IRQ3 0x0008
- #define IRQ4 0x0010
- #define IRQ5 0x0020
- #define IRQ6 0x0040
- #define IRQ7 0x0080 /* lowest - parallel printer */
- ...
-
-
-
-
- [LISTING TWO]
-
- /* [Excerpted from /sys/i386/isa/icu.h] */
- ...
- /* Interrupt "level" mechanism variables, masks, and macros */
-
- #define INTREN(s) __nonemask__ &= ~(s)
- #define INTRDIS(s) __nonemask__ |= (s)
- #define INTRMASK(msk,s) msk |= (s)
- ...
- /* [Excerpted from /sys/i386/isa/isa.c] */
- ...
- /* Configure all ISA devices */
- isa_configure() {
- struct isa_device *dvp;
- struct isa_driver *dp;
- splhigh();
- INTREN(IRQ_SLAVE);
- /* configure devices, constructing group masks as we go */
- for (dvp = isa_devtab_bio; config_isadev(dvp,&__biomask__); dvp++);
- for (dvp = isa_devtab_tty; config_isadev(dvp,&__ttymask__); dvp++);
- for (dvp = isa_devtab_net; config_isadev(dvp,&__netmask__); dvp++);
- for (dvp = isa_devtab_null; config_isadev(dvp,0); dvp++);
- /* if we support slip, then any tty interrupt is a potential net intr */
- #include "sl.h"
- #if NSL > 0
- __netmask__ |= __ttymask__;
- __ttymask__ |= __netmask__;
- #endif
-
- /* if not enabled, don't allow in ANY mask to become enabled */
- __biomask__ |= __nonemask__;
- __ttymask__ |= __nonemask__;
- __netmask__ |= __nonemask__;
- __protomask__ |= __nonemask__;
- splnone();
- }
- /* Configure an ISA device. */
- config_isadev(isdp, mp)
- struct isa_device *isdp;
- int *mp;
- {
- struct isa_driver *dp;
- if (dp = isdp->id_driver) {
- /* does this device have any I/O shared memory? */
- if (isdp->id_maddr) {
- extern int atdevbase[];
- /* convert from PC absolute physical to virtual */
- isdp->id_maddr -= IOM_BEGIN;
- isdp->id_maddr += (int)&atdevbase;
- }
- /* "Is there anyone on board?" -- Star Trek */
- isdp->id_alive = (*dp->probe)(isdp);
- if (isdp->id_alive) {
- printf("%s%d", dp->name, isdp->id_unit);
- (*dp->attach)(isdp);
- printf(" at 0x%x ", isdp->id_iobase);
- /* have we got an interrupt to wire down? */
- if(isdp->id_irq) {
- int intrno;
- intrno = ffs(isdp->id_irq)-1;
- printf("irq %d ", intrno);
- INTREN(isdp->id_irq);
- /* add to a group mask?? */
- if(mp)INTRMASK(*mp,isdp->id_irq);
- /* wire interrupt */
- setidt(ICU_OFFSET+intrno, isdp->id_intr,
- SDT_SYS386IGT, SEL_KPL);
- }
- /* perhaps a DMA channel request as well? */
- if (isdp->id_drq != -1) printf("drq %d ", isdp->id_drq);
-
- printf("on isa\n");
- }
- return (1);
- } else return(0);
- }
- ...
-
-
-
-
- [LISTING THREE
-
- /* [Excerpted from /sys/i386/include/param.h] */
-
- ...
- #ifndef __ORPL__
- /* Interrupt Group Masks */
- extern u_short __highmask__; /* interrupts masked with splhigh() */
- extern u_short __ttymask__; /* interrupts masked with spltty() */
- extern u_short __biomask__; /* interrupts masked with splbio() */
- extern u_short __netmask__; /* interrupts masked with splimp() */
- extern u_short __protomask__; /* interrupts masked with splnet() */
- extern u_short __nonemask__; /* interrupts masked with splnone() */
-
- asm(" .set IO_ICU1, 0x20 ; .set IO_ICU2, 0xa0 ");
-
- /* adjust priority level to disable a group of interrupts */
- #define __ORPL__(m) ({ u_short oldpl, msk; \
- msk = (msk); \
- asm volatile (" \
- cli ; /* modify interrupts atomically */ \
- movw %1, %%dx ; /* get mask to OR in */ \
- inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
- xchgb %%dl, %%al ; /* switch the old with the new */ \
- orb %%dl, %%al ; /* finally, OR both it in! */ \
- outb %%al, $ IO_ICU1+1 ; /* and stuff it back where it came */ \
- inb $ 0x84, %%al ; /* post it & handle write recovery */ \
- inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
- xchgb %%dh, %%al ; /* switch the old with the new */ \
- orb %%dh, %%al ; /* finally, or it in! */ \
- outb %%al, $ IO_ICU2+1 ; /* and stuff it back where it came */ \
- inb $ 0x84, %%al ; /* post it & handle write recovery */ \
- movw %%dx, %0 ; /* return old mask */ \
- sti /* allow interrupts again */ " \
- : "&=g" (oldpl) /* return values */ \
- : "g" ((m)) /* arguments */ \
- : "ax", "dx" /* registers used */ \
- ); \
- oldpl; /* return the "old" value */ \
- })
- /* force priority mask to a set value */
- #define __SETPL__(m) ({ u_short oldpl, msk; \
- msk = (msk); \
- asm volatile (" \
- cli ; /* modify interrupts atomically */ \
- movw %1, %%dx ; /* get mask to OR in */ \
- inb $ IO_ICU1+1, %%al ; /* get low order mask */ \
- xchgb %%dl, %%al ; /* switch the old with the new */ \
- outb %%al, $ IO_ICU1+1 ; /* and stuff it back where it came */ \
- inb $ 0x84, %%al ; /* post it & handle write recovery */ \
- inb $ IO_ICU2+1, %%al ; /* next, get high order mask */ \
- xchgb %%dh, %%al ; /* switch the old with the new */ \
- outb %%al, $ IO_ICU2+1 ; /* and stuff it back where it came */ \
- inb $ 0x84, %%al ; /* post it & handle write recovery */ \
- movw %%dx, %0 ; /* return old mask */ \
- sti /* allow interrupts again */ " \
- : "&=g" (oldpl) /* return values */ \
- : "g" ((m)) /* arguments */ \
- : "ax", "dx" /* registers used */ \
- ); \
- oldpl; /* return the "old" value */ \
- })
- #define splhigh() __ORPL__(__highmask__)
- #define spltty() __ORPL__(__ttymask__)
- #define splbio() __ORPL__(__biomask__)
- #define splimp() __ORPL__(__netmask__)
- #define splnet() __ORPL__(__protomask__)
- #define splsoftclock() __ORPL__(__protomask__)
- #define splx(v) ({ u_short val; \
- val = (v); \
- if (val == __nonemask__) (void) spl0(); /* zero is special */ \
- else (void) __SETPL__(val); \
- })
- #endif __ORPL__
- ...
-
-
-
-
- [LISTING FOUR]
-
- /* [Excerpted from /sys/i386/i386/machdep.c] */
-
- ...
- /* Fill out a gate descriptor uses as an interrupt vector. */
- setidt(idx, func, typ, dpl) char *func; {
- struct gate_descriptor *ip = idt + idx;
- ip->gd_looffset = (int)func;
- ip->gd_selector = GSEL(GCODE_SEL,SEL_KPL);
- ip->gd_stkcpy = 0;
- ip->gd_xx = 0;
- ip->gd_type = typ;
- ip->gd_dpl = dpl; /* can we allow INT's to this IDT index? */
- ip->gd_p = 1; /* yup, we're here, don't segment fault me */
- ip->gd_hioffset = ((int)func)>>16 ;
- }
- ...
-
-
-
-
- [LISTING FIVE]
-
- /* [Excerpted from /sys/i386/include/segments.h] */
-
- ...
- /* Gate descriptors (e.g. indirect descriptors)
- * [The IDT is made up of these as well.] */
- struct gate_descriptor {
- unsigned gd_looffset:16 ; /* gate offset (lsb) */
- unsigned gd_selector:16 ; /* gate segment selector */
- unsigned gd_stkcpy:5 ; /* number of stack wds to cpy */
- unsigned gd_xx:3 ; /* unused */
- unsigned gd_type:5 ; /* segment type */
- unsigned gd_dpl:2 ; /* segment descriptor priority level */
- unsigned gd_p:1 ; /* segment descriptor present */
- unsigned gd_hioffset:16 ; /* gate offset (msb) */
- } ;
- ...
-
-
-
-